/** @file    BundleLoader.cpp
 *  @author  Alessandro Polo
 *  @version $Id: BundleLoader.cpp 2559 2010-05-27 01:56:43Z alex $
 *  @brief
 * File containing methods for the wosh::BundleLoader class.
 * The header for this class can be found in BundleLoader.h, check that file
 * for class description.
 ****************************************************************************/
/* Copyright (c) 2007-2010, WOSH - Wide Open Smart Home 
 * by Alessandro Polo - OpenSmartHome.com
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the OpenSmartHome.com WOSH nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY Alessandro Polo ''AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL Alessandro Polo BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ****************************************************************************/

 #include <core/BundleLoader.h>

 #include <core/Utilities.h>
 #include <core/FileSystem.h>
 #include <algorithm> // folder parsing (sorting)
 #include <fstream>

 #include <core/BundleRequirements.h>
 #include <core/BundleManager.h>
 #include <core/WoshKernel.h>
 #include <core/SystemError.h>
 #include <core/MethodsCommon.h>
 #include <core/Table.h>
 #include <core/SecurityManager.h>
 #include <core/ObjectFactory.h>
 #include <core/ThreadMethod.h>


using namespace std;
namespace wosh {


//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

BundleAction* BundleAction::fromString( LogContext& log, const string& dataLine ) {
	std::vector<std::string> results;
	Utilities::splitString( dataLine, " ", results, false, true );
	if ( results.size() < 2 ) {
		return NULL;
	 }
	if ( results.at(0) == "BundleLoad" ) {
		BundleActionLoad* action = new BundleActionLoad(log);
		action->bundle_type.name = results.at(1);
		if ( results.size() > 2 )
			action->bundle_name = results.at(2);
		return action;
	 }
	else if ( results.at(0) == "BundleStart" ) {
		BundleActionStart* action = new BundleActionStart(log);
		action->bundle_name = results.at(1);
		return action;
	 }
	else if ( results.at(0) == "BundleStop" ) {
		BundleActionStop* action = new BundleActionStop(log);
		action->bundle_name = results.at(1);
		return action;
	 }
	else if ( results.at(0) == "BundleUnLoad" ) {
		BundleActionUnLoad* action = new BundleActionUnLoad(log);
		action->bundle_name = results.at(1);
		return action;
	 }
	return NULL;
 }

BundleAction* BundleAction::fromBundleState( LogContext& log, Bundle::BUNDLE_STATE state ) {
	switch(state) {
		case Bundle::STATE_STARTED: return new BundleActionStart(log);
		case Bundle::STATE_STOPPED: return new BundleActionStop(log);
		case Bundle::STATE_DESTROYED: return new BundleActionUnLoad(log);
		default: return NULL;
	 }
	return NULL;
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
class BundleActionExec : public ThreadMethod
 {
	public:
		BundleActionExec( const Object* owner, BundleAction* bundle_action )
			: ThreadMethod(owner, "BundleAction"), action(bundle_action) {}
	public:
		void work() {
			if ( this->action != NULL )
			this->action->execute();
		 }

	protected:
		BundleAction* action;
};

WRESULT BundleAction::executeAsynch( unsigned long timeout ) {
	BundleActionExec runner( BundleManager::getInstance(), this );
	WRESULT started = runner.startThread(timeout);
	if ( WFAILED(started) )
		return WRET_ERR_INTERNAL;

	if ( runner.waitState(&runner, Thread::STATE_STOPPED, timeout) )
		return this->result_ret;
	runner.quitThread(timeout);
	return WRET_ERR_ILLEGAL_USE;
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////

void BundleAction::succeded() {
	this->executedTs = Utilities::std_time();
	this->result = BundleAction::RESULT_SUCCEDED;
	this->result_ret = WRET_OK;
 }

void BundleAction::failed( WRESULT ret, ACTION_RESULT result  ) {
	this->executedTs = Utilities::std_time();
	this->result = result;
	this->result_ret = ret;
 }

ListT<Bundle*>& BundleAction::getBundles() {
	return BundleManager::getInstance()->bundles;
 }
Bundle* BundleAction::getBundleByName_() {
	return BundleManager::getInstance()->getBundleByName_(this->bundle_name);
 }

BundleManager* BundleAction::getBundleManager() {
	return BundleManager::getInstance();
 }


Mutex& BundleAction::getStateTransitionMux() {
	return BundleManager::getInstance()->stateTransitionMux;
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////

WRESULT BundleAction::applySettingTo( Bundle* bundle ) {
	if ( bundle == NULL ) return WRET_ERR_PARAM;
	// BUG not reentrant
	PropertiesProvider* bProp = WoshKernel::getInstance()->settings().getSettingsOf( bundle->getName() );
	if ( bProp == NULL ) {
		BundleManager::getInstance()->Log(LOG_WARNING, ":applySettingTo(%s) : default settings not found", bundle->getName().c_str() );
		return WRET_ERR_INTERNAL;
	 }
	BundleManager::getInstance()->Log(LOG_INFO, ":applySettingTo(%s) : Applying %d default settings", bundle->getName().c_str(), bProp->count() );
	if ( bundle->bundleProperties() == NULL ) {
		Request* sets_request = new Request( _METHOD_SetProperties, bProp->toTable(true) );
		Message* message = new Message(sets_request);
		message->setSource( BundleManager::getInstance() );
		message->setSourceBus( _Bus_Core );
		message->setDestination( bundle->getURI() );
		SecurityManager::getCredentialImplicit().signMessage(message, BundleManager::getInstance());
		bundle->busMessage( *message, NULL );
		delete message;
	 }
	else { // optimized
		bundle->bundleProperties()->intersect(*bProp, true, false);
	 }
	return WRET_OK;
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////

// validate current state and state mask
WRESULT BundleAction::validateTransitionState( Bundle* bundle, Bundle::BUNDLE_STATE new_state, int allowed_states_mask ) {
	if ( bundle == NULL ) return WRET_ERR_PARAM;
	if ( bundle->getBundleState() == new_state ) {
		Log(LOG_CRITICAL, ":validateTransition(%s,%s) : Invalid state, already %s", bundle->getName().c_str(), Bundle::getBundleStateAsString(new_state), bundle->getBundleStateAsString()  );
		return WRET_ERR_ILLEGAL_USE;
	 }
	if ( ( (int)bundle->getBundleState() & allowed_states_mask) == false ) {
		Log(LOG_CRITICAL, ":validateTransition(%s,%s) : Invalid state against mask %d [%s]", bundle->getName().c_str(), Bundle::getBundleStateAsString(new_state), allowed_states_mask, bundle->getBundleStateAsString() );
		return WRET_ERR_ILLEGAL_USE;
	 }
	return WRET_OK;
 }

// validate current state and state mask
WRESULT BundleAction::validateTransitionRequirements( Bundle* bundle, Bundle::BUNDLE_STATE state_scope ) {
	if ( bundle == NULL ) return WRET_ERR_PARAM;
	const BundleRequirements* reqs = bundle->bundleRequirements();
	if ( reqs == NULL )
		return WRET_OK;

	vector<BundleRequirement*> req_list;
	reqs->getRequirementsOf( req_list, state_scope );
	if ( req_list.empty() )
		return WRET_OK;

	// analyze reqs

	return WRET_OK;

 }

// validate current state and state mask
WRESULT BundleAction::validateConflictsRequirements( Bundle* bundle, Bundle::BUNDLE_STATE state_scope ) {
	if ( bundle == NULL ) return WRET_ERR_PARAM;
/*
	tBundleList::Iterator it;
	const tBundleList::ConstIterator it_end = this->bundles.end();
	for ( it=this->bundles.begin(); it!=it_end; ++it ) {
		if ( *it == NULL ) continue;
		if ( (*it)->bundleRequirements() == NULL ) continue;
		vector<BundleRequirement*> req_list;
		(*it)->bundleRequirements()->getRequirementsOf(req_list, (*it)->getBundleState() );
		if ( req_list.empty() )
			continue;
		vector<BundleRequirement*>::iterator itr;
		for ( itr=req_list.begin(); itr!=req_list.end(); ++itr ) {
			if ( *itr == NULL ) continue;
			if ( (*itr)->getClassType() != this->bundle_type.name )
				continue;
			// validate requirement of current bundle against loading 'bundle_type'
			
		 }
//TODO
	 }
*/
	return WRET_OK;
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

void BundleActionLoad::execute() {
	getBundles().transactionBeginWrite();
	// allocate object
	Bundle* bundle = ObjectFactory::createTypeOf<Bundle>(this->bundle_type.name, this->bundle_type.version);
	if ( bundle == NULL ) { // unable to allocate type
		getBundles().transactionEnd();
		failed(WRET_ERR_PARAM);
		return;
	 }
	// overwrite name?
	if ( !this->bundle_name.empty() )
		bundle->setName(bundle_name);

	// avoid other bundles to change state while validating requirements and loading this bundle
	getStateTransitionMux().lock();

//TODO validate conflicts: (requirements of other bundles)

	// register bundle, pointer ownership is lost!
	// may fail if bundle is already loaded



	WRESULT reg = getBundleManager()->registerBundle_( bundle );
	if ( WFAILED(reg) ) {
		getStateTransitionMux().unLock();
		getBundles().transactionEnd();
		if ( reg != WRET_ERR_ILLEGAL_USE) // free the bundle
			delete bundle;
		failed(reg);
		return;
	 }
	getStateTransitionMux().unLock();
	if ( apply_settings ) {
		WRESULT settings_applied = applySettingTo( bundle );
		(void)settings_applied;
	 }
	getBundles().transactionEnd();
	succeded();
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

void BundleActionStart::execute() {
	getBundles().transactionBeginRead();
	Bundle* bundle = getBundleByName_();
	getStateTransitionMux().lock();
	WRESULT state_validated = validateTransitionState(bundle, Bundle::STATE_STARTED, Bundle::STATE_STOPPED | Bundle::STATE_CREATED );
	if ( WFAILED(state_validated) ) {
		getStateTransitionMux().unLock();
		getBundles().transactionEnd();
		Log(LOG_CRITICAL, ":doStart(%s) : FAILED#%d Validating state", this->bundle_name.c_str(), state_validated );
		failed(state_validated);
		return;
	 }
	WRESULT state_reqs = validateTransitionRequirements(bundle, Bundle::STATE_STARTED );
	if ( WFAILED(state_reqs) ) {
		getStateTransitionMux().unLock();
		getBundles().transactionEnd();
		Log(LOG_CRITICAL, ":doStart(%s) : FAILED#%d Validating requirements", this->bundle_name.c_str(), state_reqs );
		failed(state_reqs);
		return;
	 }
	WRESULT state_conflicts = validateConflictsRequirements(bundle, Bundle::STATE_STARTED );
	if ( WFAILED(state_conflicts) ) {
		getStateTransitionMux().unLock();
		getBundles().transactionEnd();
		Log(LOG_CRITICAL, ":doStart(%s) : FAILED#%d Validating requirements", this->bundle_name.c_str(), state_conflicts );
		failed(state_conflicts);
		return;
	 }
	Log(LOG_INFO, ":doStart(%s) : Starting Bundle..", this->bundle_name.c_str() );
	WRESULT ret = bundle->bundleStart();
	if ( WFAILED(ret) ) {
		getStateTransitionMux().unLock();
		getBundles().transactionEnd();
		SystemError::raise(getBundleManager(), Log, SystemError::CRITICAL, 0, "doStart", "[%s] FAILED bundleStart() returned %d", this->bundle_name.c_str(), ret );
		failed(ret);
		return;
	 }
	Log(LOG_VERBOSE, ":doStart(%s) : Waiting for STARTED state..", this->bundle_name.c_str() );
	bool started = BundleManager::waitState(bundle, Bundle::STATE_STARTED);
	if ( !started ) {
		getStateTransitionMux().unLock();
		getBundles().transactionEnd();
		SystemError::raise(getBundleManager(), Log, SystemError::CRITICAL, 0, "doStart", "[%s] FAILED waiting for STARTED state", this->bundle_name.c_str() );
		failed(WRET_ERR_INTERNAL);
		return;
	 }
	getStateTransitionMux().unLock();
	getBundles().transactionEnd();
	Log(LOG_VERBOSE, ":doStart(%s) : Bundle is running.", this->bundle_name.c_str() );
	succeded();
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

void BundleActionStop::execute() {
	getBundles().transactionBeginRead();
	Bundle* bundle = getBundleByName_();
	getStateTransitionMux().lock();
	WRESULT state_validated = validateTransitionState(bundle, Bundle::STATE_STOPPED, Bundle::STATE_STARTED );
	if ( WFAILED(state_validated) ) {
		getStateTransitionMux().unLock();
		getBundles().transactionEnd();
		Log(LOG_CRITICAL, ":doStop(%s) : FAILED#%d Validating state", this->bundle_name.c_str(), state_validated );
		failed(state_validated);
		return;
	 }
	WRESULT state_reqs = validateTransitionRequirements(bundle, Bundle::STATE_STOPPED );
	if ( WFAILED(state_reqs) ) {
		getStateTransitionMux().unLock();
		getBundles().transactionEnd();
		Log(LOG_CRITICAL, ":doStop(%s) : FAILED#%d Validating requirements", this->bundle_name.c_str(), state_reqs );
		failed(state_reqs);
		return;
	 }
	WRESULT state_conflicts = validateConflictsRequirements(bundle, Bundle::STATE_STOPPED );
	if ( WFAILED(state_conflicts) ) {
		getStateTransitionMux().unLock();
		getBundles().transactionEnd();
		Log(LOG_CRITICAL, ":doStop(%s) : FAILED#%d Validating requirements", this->bundle_name.c_str(), state_conflicts );
		failed(state_conflicts);
		return;
	 }
	Log(LOG_INFO, ":doStop(%s) : Stopping Bundle..", this->bundle_name.c_str() );
	WRESULT ret = bundle->bundleStop();
	if ( WFAILED(ret) ) {
		getStateTransitionMux().unLock();
		getBundles().transactionEnd();
		SystemError::raise(getBundleManager(), Log, SystemError::CRITICAL, 0, "doStart", "[%s] FAILED bundleStop() returned %d", this->bundle_name.c_str(), ret );
		failed(ret);
		return;
	 }
	Log(LOG_VERBOSE, ":doStop(%s) : Waiting for STOPPED state..", this->bundle_name.c_str() );
	bool started = BundleManager::waitState(bundle, Bundle::STATE_STOPPED);
	if ( !started ) {
		getStateTransitionMux().unLock();
		getBundles().transactionEnd();
		SystemError::raise(getBundleManager(), Log, SystemError::CRITICAL, 0, "doStart", "[%s] FAILED waiting for STARTED state", this->bundle_name.c_str() );
		failed(WRET_ERR_INTERNAL);
		return;
	 }
	getStateTransitionMux().unLock();
	getBundles().transactionEnd();
	Log(LOG_VERBOSE, ":doStop(%s) : Bundle is stopped.", this->bundle_name.c_str() );
	succeded();
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

void BundleActionUnLoad::execute() {
	getBundles().transactionBeginWrite();
	Bundle* bundle = getBundleByName_();
	getStateTransitionMux().lock();
	WRESULT state_validated = validateTransitionState(bundle, Bundle::STATE_DESTROYED, Bundle::STATE_STOPPED );
	if ( WFAILED(state_validated) ) {
		getStateTransitionMux().unLock();
		getBundles().transactionEnd();
		Log(LOG_CRITICAL, ":doUnload(%s) : FAILED#%d Validating state", this->bundle_name.c_str(), state_validated );
		failed(state_validated);
		return;
	 }
	WRESULT state_reqs = validateTransitionRequirements(bundle, Bundle::STATE_DESTROYED );
	if ( WFAILED(state_reqs) ) {
		getStateTransitionMux().unLock();
		getBundles().transactionEnd();
		Log(LOG_CRITICAL, ":doUnload(%s) : FAILED#%d Validating requirements", this->bundle_name.c_str(), state_reqs );
		failed(state_reqs);
		return;
	 }
	WRESULT state_conflicts = validateConflictsRequirements(bundle, Bundle::STATE_DESTROYED );
	if ( WFAILED(state_conflicts) ) {
		getStateTransitionMux().unLock();
		getBundles().transactionEnd();
		Log(LOG_CRITICAL, ":doUnload(%s) : FAILED#%d Validating requirements", this->bundle_name.c_str(), state_conflicts );
		failed(state_conflicts);
		return;
	 }
	getBundles().pop(bundle);
	Log(LOG_INFO, ":doUnload(%s) : Destroying instance..", this->bundle_name.c_str() );
	ObjectFactory::destroy(bundle);

	getStateTransitionMux().unLock();
	getBundles().transactionEnd();
	Log(LOG_VERBOSE, ":doUnload(%s) : Bundle is stopped.", this->bundle_name.c_str() );
	succeded();
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

















//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////// CONSTRUCTORS

BundleLoader::BundleLoader() : Object()
 {
	Object::setName( "BundleLoader" );

	Log.setContext( "BundleLoader" );
	Log.setIndent( 3 );
	Log.setLevel( LOG_INFO );
 }

BundleLoader::~BundleLoader()
 {
	Log(LOG_VERBOSE, ":~BundleLoader() : Deleting Actions.." );
	this->bundleActions.clear();
 }

//////////////////////////////////////////////////////////////////////////////////////////////// CONSTRUCTORS
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

WRESULT BundleLoader::loadFromArgs( int argc, char **argv )
 {
	if ( argc == 0 || argv == NULL ) {
		Log(LOG_VERBOSE, ":loadFromArgs() : No Arguments.." );
		return WRET_ERR_PARAM;
	 }
	// DEPRECATED
	Log(LOG_CRITICAL, ":loadFromArgs() : NOT IMPLEMENTED" );
	return WRET_ERR_INTERNAL;
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////// FILE PARSING

WRESULT BundleLoader::loadActionsFile( const std::string& filename )
 {
	if ( filename.size() == 0 ) {
		Log(LOG_CRITICAL, ":loadActionsFile('') empty filename!" );
		return WRET_ERR_PARAM;
	 }
	ifstream infile;
	infile.open( filename.c_str(), ifstream::in );
	if ( !infile.is_open() ) {
		Log(LOG_CRITICAL, ":loadActionsFile('%s') : Invalid filename (can't open)", filename.c_str() );
		return WRET_ERR_PARAM;
	 }
 	Log(LOG_VERBOSE, ":loadActionsFile('%s') : Parsing file..", filename.c_str() );

	string buffer;
	string cGroup = "";
	size_t cPos;
	long iLine = 0;

	this->bundleActions.transactionBeginWrite();
	while ( infile.good() ) {
		if ( infile.eof() )	break;
		getline( infile, buffer);
		++iLine;
		// ignore comments
		cPos = buffer.find('#');
		if ( cPos != string::npos )
			buffer.erase( cPos );
		// remove endline
		cPos = buffer.find('\r');
		if ( cPos != string::npos )
			buffer.erase( cPos );
		cPos = buffer.find('\n');
		if ( cPos != string::npos )
			buffer.erase( cPos );
		Utilities::trimSpaces(buffer, 2);
		// ignore empty lines or comment-cleaned
		if ( buffer.empty() ) continue;
		// buffer ready, parse the line
		parseLine_( buffer );
	 }
	this->bundleActions.transactionEnd();

	infile.close();
	Log(LOG_VERBOSE, ":loadActionsFile(%s) : Loaded %d actions", filename.c_str(), this->bundleActions.count() );
	return WRET_OK;
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////

WRESULT BundleLoader::loadActionsFolder( const std::string& folder, const std::string& pattern )
 {
	FilePath cfgPath;
	if ( !cfgPath.set( folder ) ) {
		Log(LOG_CRITICAL, ":loadActionsFolder() : FAILED resolving %s", folder.c_str() );
		return WRET_ERR_PARAM;
	 }
	if ( !cfgPath.isFolder() ) {
		Log(LOG_CRITICAL, ":loadActionsFolder() : FAILED %s is NOT a valid Folder", cfgPath.getPathLocal().c_str() );
		return WRET_ERR_PARAM;
	 }

	WRESULT ret = WRET_OK;
	vector<string> files;
	ret = FileSystem::getFilesOf( cfgPath.getPathLocal(), files, false );
	if ( WFAILED(ret) ) {
		Log(LOG_CRITICAL, ":loadActionsFolder() : FAILED getting files of %s", cfgPath.getPathLocal().c_str() );
		return ret;
	 }
	if ( files.empty() ) {
		Log(LOG_WARNING, ":loadActionsFolder() : No files found in %s", cfgPath.getPathLocal().c_str() );
		return WRET_ERR_PARAM;
	 }
	Log(LOG_VERBOSE, ":loadActionsFolder() : %d files found in %s", files.size(), cfgPath.getPathLocal().c_str() );

	std::sort( files.begin(), files.end() );
	std::vector<string>::const_iterator it;
	for ( it=files.begin(); it!=files.end(); ++it ) {
		if ( (*it).find(pattern) == string::npos )
			continue;
		// loadActionsFile is reentrant
		ret += loadActionsFile( FilePath::combine(cfgPath.getPathLocal(), *it) );
	 }

	Log(LOG_INFO, ":loadActionsFolder('%s',%s) : Loaded %d actions", folder.c_str(), pattern.c_str(), this->bundleActions.count() );
 	return ret;
 }

//////////////////////////////////////////////////////////////////////////////////////////////// FILE PARSING
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////// LINE PARSING

WRESULT BundleLoader::parseLine_( const std::string& dataLine )
 {
	BundleAction* action = BundleAction::fromString(this->Log, dataLine);
	if ( action == NULL )
		return WRET_ERR_PARAM;
	this->bundleActions.push_back(action);
	return WRET_OK;
 }

//////////////////////////////////////////////////////////////////////////////////////////////// LINE PARSING
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

WRESULT BundleLoader::createActions( tBundleActionList& actions, Bundle::BUNDLE_STATE state_transition )
 {
	tBundleList::Iterator it;
	const tBundleList::ConstIterator it_end = BundleManager::getInstance()->bundles.end();
	for ( it=BundleManager::getInstance()->bundles.begin(); it!=it_end; ++it ) {
		if ( *it == NULL ) continue;
		BundleAction* action = BundleAction::fromBundleState( Log, state_transition );
		if ( action == NULL ) continue;
		action->bundle_name = (*it)->getName();
		actions.push_back(action);
	 }
	return WRET_OK;
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

WRESULT BundleLoader::executeActions( tBundleActionList& actions, BundleAction::ACTION_TYPE type )
 {
	tBundleActionList::Iterator it;
	const tBundleActionList::ConstIterator it_end = actions.end();
	for ( it=actions.begin(); it!=it_end; ++it ) {
		if ( *it == NULL ) continue;
		if (type != BundleAction::ACTION_UNKNOWN && (*it)->getType() != type ) continue;
		
		(*it)->execute();

	 }

	return WRET_OK;
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////


}; // namespace wosh
